package com.luo.ai.assistant.file.impl;

import com.luo.ai.assistant.file.FileConvertor;
import com.luo.ai.assistant.file.MyFileStorageService;
import com.luo.ai.assistant.file.dao.FileDetailMapper;
import com.luo.ai.assistant.file.model.FileDetail;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 文件存储服务
 *
 * @author luohq
 * @date 2025-01-02 10:01
 */
@Service
public class MyFileStorageServiceImpl implements MyFileStorageService {
    private Logger log = LoggerFactory.getLogger(MyFileStorageServiceImpl.class);

    /**
     * 底层文件存储服务
     */
    private final FileStorageService fileStorageService;
    /**
     * 文件数据库记录Mapper
     */
    private final FileDetailMapper fileDetailMapper;
    /**
     * 向量存储服务
     */
    private final VectorStore vectorStore;

    public MyFileStorageServiceImpl(FileStorageService fileStorageService,
                                    FileDetailMapper fileDetailMapper,
                                    VectorStore vectorStore) {
        this.fileStorageService = fileStorageService;
        this.fileDetailMapper = fileDetailMapper;
        this.vectorStore = vectorStore;
    }

    @Override
    public FileInfo uploadFile(MultipartFile file, Map<String, String> metadata) {
        FileInfo fileInfo = this.fileStorageService.of(file)
                //.setOriginalFilename("")
                //.setMetadata(metadata)
                .upload();
        //扩展元数据
        this.extendFileMetadata(fileInfo, metadata);
        return fileInfo;
    }

    @Override
    public FileInfo uploadFile(File file, Map<String, String> metadata) {
        FileInfo fileInfo = this.fileStorageService.of(file)
                //.setOriginalFilename("")
                //.setMetadata(metadata)
                .upload();
        //扩展元数据
        this.extendFileMetadata(fileInfo, metadata);
        return fileInfo;
    }

    /**
     * Extend file metadata
     *
     * @param fileInfo file info
     * @param metadata metadata
     */
    private void extendFileMetadata(FileInfo fileInfo, Map<String, String> metadata) {
        //附加额外的文件元数据
        metadata.put("fileId", fileInfo.getId());
        metadata.put("fileOriginalName", fileInfo.getOriginalFilename());
        //更新元数据（兼容Local文件存储不支持设置元数据的问题）
        this.fileDetailMapper.updateMetadata(fileInfo.getId(), metadata);
        //回写元数据
        fileInfo.setMetadata(metadata);
    }

    @Override
    public void downloadFileToOutputStream(String fileUrl, OutputStream outputStream) {
        this.fileStorageService.download(fileUrl).outputStream(outputStream);
    }

    @Override
    public byte[] downloadFileAsBytes(String fileUrl) {
        return this.fileStorageService.download(fileUrl).bytes();
    }

    @Override
    public OutputStream downloadFileAsOutputStream(String fileUrl) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        this.fileStorageService.download(fileUrl).outputStream(byteArrayOutputStream);
        return byteArrayOutputStream;
    }

    @Override
    public Resource downloadFileAsResource(String fileUrl) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        this.fileStorageService.download(fileUrl).outputStream(byteArrayOutputStream);
        //byteArrayOutStream转换成Spring Resource
        return new ByteArrayResource(byteArrayOutputStream.toByteArray());
    }

    @Override
    public File downloadFile(FileInfo fileInfo) {
        //TODO 需添加TEMP_DIR前缀
        File targetFile = new File(fileInfo.getFilename());
        this.fileStorageService.download(fileInfo).file(targetFile);
        return targetFile;
    }

    @Override
    public FileSystemResource downloadFileAsResource(FileInfo fileInfo) {
        File targetFile = this.downloadFile(fileInfo);
        return new FileSystemResource(targetFile);
    }


    @Override
    public void deleteFile(String fileUrl) {
        this.fileStorageService.delete(fileUrl);
    }

    @Override
    public void deleteFileByIds(List<String> ids) {
        //查询文件记录列表
        List<FileDetail> fileDetails = this.fileDetailMapper.findByIds(ids);
        if (CollectionUtils.isEmpty(fileDetails)) {
            return;
        }
        //删除文件
        log.info("删除文件存储：{}", ids);
        fileDetails.stream()
                .map(FileConvertor::toFileInfo)
                .forEach(this.fileStorageService::delete);

        //删除文件关联的向量文档集合
        List<String> documentIds = fileDetails.stream()
                .map(FileDetail::getDocumentIds)
                .filter(docIds -> StringUtils.hasText(docIds))
                .flatMap(docIds -> Stream.of(docIds.split(",")))
                .toList();
        if (!CollectionUtils.isEmpty(documentIds)) {
            //删除向量
            log.info("删除向量存储：{}", documentIds);
            this.vectorStore.delete(documentIds);
        }
    }
}